/**
 * FFMpeg解码音视频过程:
 *  1.获取解码器 avcodec_find_decoder_by_name(codec_name)
 *  2.初始化解码器上下文 avcodec_alloc_context3(pCodec)
 *  3.设置解码器上下文参数
 *  4.打开解码器上下文 avocdec_open2(pCodecCtx, pCodec, ppOptions)
 *  5.初始化AVFrame，供解码使用 av_frame_alloc()
 *以上是初始化解码器上下文过程
 *  6.往解码器发送数据包(AVPacket) avcodec_send_packet(pCodecCtx, pPacket)
 *  7.等待接受解码好的数据帧(AVFrame)做另外处理 avcodec_receive_frame(pCodecCtx, pFrame)
 *以上是使用解码器解码音视频的操作
 *  8.停止解码器，需要往解码器中传输空包，冲刷解码器 avcodec_send_packet(pCodecCtx, nullptr)
 *  9.关闭解码器上下文 avcodec_close(pCodecCtx)
 *  10.释放解码器上下文 avcodec_free_context(ppCodecCtx)
 *以上是释放解码器上下过程
 *
 */

#include "FFMpegDecoder.h"

#define LOG_TAG "FFMpegDecoder"

bool FFMpegDecoder::initDecoder(DecoderParam &decodeParam) {
  auto pCodec = findCodec(decodeParam);
  if (!pCodec) {
    LOG_ERROR("findCodec error.")
    return false;
  }

  _pCodecCtx = avcodec_alloc_context3(pCodec);
  if (_pCodecCtx == nullptr) {
    LOG_ERROR("avcodec_alloc_context3 error.")
    return false;
  }

  _pCodecCtx->codec_id = pCodec->id;
  _pCodecCtx->codec_type = pCodec->type;
  _pCodecCtx->codec_tag = 0;
  int32_t ret = initContextParam(_pCodecCtx, decodeParam);
  if (ret != SUCCESS) {
    releaseDecoder();
    LOG_ERROR("initContextParam error.")
    return false;
  }

  ret = avcodec_open2(_pCodecCtx, pCodec, &_pOptions);
  if (ret < SUCCESS) {
    releaseDecoder();
    LOG_ERROR("avcodec_open2 error. errCode:%d, errStr:%s", ret, av_err2str(ret))
    return false;
  }

  _pFrame = av_frame_alloc();
  _State = DecoderState_Init;
  return true;
}

void FFMpegDecoder::releaseDecoder() {
  if (_State == DecoderState_Init || _State == DecoderState_Decode) {
    startDecode(nullptr);
  }

  _State = DecoderState_Release;

  if (_pFrame) {
    av_frame_free(&_pFrame);
    _pFrame = nullptr;
  }

  if (_pCodecCtx) {
    avcodec_close(_pCodecCtx);
    avcodec_free_context(&_pCodecCtx);
    _pCodecCtx = nullptr;
  }

  _State = DecoderState_None;
}

bool FFMpegDecoder::startDecode(AVPacket *pPacket) {
  if (_State == DecoderState_None)
    return false;

  int32_t ret = SUCCESS;
  if (pPacket) {
    ret = av_packet_make_writable(pPacket);
    if (ret < 0) {
      LOG_ERROR("av_packet_make_writable error. errCode:%d, errStr:%s", ret,
                av_err2str(ret))
      return false;
    }
  }

  ret = avcodec_send_packet(_pCodecCtx, pPacket);
  while (ret >= SUCCESS) {
    _State = DecoderState_Decode;
    ret = avcodec_receive_frame(_pCodecCtx, _pFrame);
    if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
      break;
    } else if (ret < SUCCESS) {
      LOG_ERROR("avcodec_receive_frame error. errCode:%d, errStr:%s", ret,
                av_err2str(ret))
      return false;
    }

    if (_pDecoderCallback) {
      _pDecoderCallback->onDecodeData(this, _pFrame);
    }

    av_frame_unref(_pFrame);
  }

  _State = DecoderState_Init;
  return true;
}
